﻿package src.entity 
{
	/**
	* 
	* Reliability project
	* -----------------------
	* @author  Dmitrij Boycov
	* @mail    dmitry.boycov@gmail.com
	* @date    April 27, 2010
	* @version 1
	* 
	*/
	
	import flash.display.DisplayObject;
	import flash.events.MouseEvent;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.utils.Dictionary;
	import flash.filters.BlurFilter;
	//
	import src.computation.CLink;

	public class Link extends Entity implements IEntity{
	
		
		// for identification into parent scheme
		public static const TYPE:String = "LINK";	
		//
		private var line:Sprite;
		private var endLine:Sprite;
		private var startLine:Sprite;
		private var endEntity = null;
		private var startEntity = null;
		//
		private var lColour = 0x000000;
		private var cRadius = 2;
		private var activeEnd:String;
		private var scheme;
		/*
		* constructor
		*/ 
		public function Link(){
			super();
			this.line = new Sprite();
			this.line.name = "LINE";
			this.line.doubleClickEnabled = true;
			this.line.buttonMode = true;
			this.line.graphics.lineStyle(2, lColour);
			this.line.addEventListener(MouseEvent.DOUBLE_CLICK, onDoubleClick);
			this.line.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
			this.line.addEventListener(MouseEvent.MOUSE_UP, onUp);
			addChild(this.line);
			this.startLine = createCircle(); 
			this.startLine.name = "startLine"; 
			this.startLine.x = 0;
			this.startLine.y = 0;
			this.startLine.addEventListener(MouseEvent.MOUSE_DOWN, startMoveStartLine);
			this.startLine.addEventListener(MouseEvent.MOUSE_UP, stopMoveStartLine);
			this.startLine.addEventListener(MouseEvent.DOUBLE_CLICK, onDoubleClick);
			addChild(startLine);
			this.endLine = createCircle();
			this.endLine.name = "endLine";
			this.endLine.x = 0;
			this.endLine.y = 0;
			this.endLine.addEventListener(MouseEvent.MOUSE_DOWN, startMoveEndLine);
			this.endLine.addEventListener(MouseEvent.MOUSE_UP, stopMoveEndLine);
			this.endLine.addEventListener(MouseEvent.DOUBLE_CLICK, onDoubleClick);
			addChild(endLine);
			//
			this.illuminateObj = new Sprite();			
			this.illuminateObj.graphics.beginFill(0x30b1e7);
			this.illuminateObj.graphics.lineStyle(2, 0x30b1e7);
			this.illuminateObj.doubleClickEnabled = true;
			this.illuminateObj.graphics.endFill();
			this.illuminateObj.filters =[new BlurFilter(5,5,3)];
		}
		// seters
		public function setParent(scheme) {
			this.scheme = scheme;
		}
		// geters		
		public override function getType():String{
			return Link.TYPE;
		}
		
		public function unlink() {
			if (this.endEntity != null) {
				this.endEntity.removeLink(this);
			}
			if (this.startEntity != null) {
				this.startEntity.removeLink(this);
			}
		}
		
		public function replaceEntity(newEnt, oldEnt) {
			var pc, pe:Point;
			if (oldEnt == this.endEntity) {
				this.endEntity = newEnt;				
				pe = new Point(this.startLine.x, this.startLine.y);
				pc = new Point(this.endLine.x, this.endLine.y);				
				pc = this.localToGlobal(pc);
				pe = this.localToGlobal(pe);
				pc = this.globalToLocal(this.endEntity.getConnectPoint(pc, pe, this));
				this.endLine.x = pc.x;
				this.endLine.y = pc.y;
			}
			if (oldEnt == this.startEntity) {
				this.startEntity = newEnt;
				pc = new Point(this.startLine.x, this.startLine.y);
				pe = new Point(this.endLine.x, this.endLine.y);				
				pc = this.localToGlobal(pc);
				pe = this.localToGlobal(pe);
				pc = this.globalToLocal(this.startEntity.getConnectPoint(pc, pe, this));
				this.startLine.x = pc.x;
				this.startLine.y = pc.y;
			}
			this.reDrawLine(this.startLine,this.endLine);
		}
		
		public function getEndEntity() {
			return this.endEntity;
		}
		public function getStartEntity() {
			return this.startEntity;
		}
		///
		public function startDraw(e:MouseEvent) {
			this.activeEnd = "End";
			dispatchEvent(new Event(Entity.ENTITY_ON_DOWN));
		}
		///
		private function createCircle() {
			var circle:Sprite = new Sprite();
			circle.doubleClickEnabled = true;
			circle.graphics.lineStyle(1);
			circle.graphics.beginFill(lColour);			
			circle.graphics.drawCircle(0,0,cRadius);
			circle.graphics.endFill();			
			circle.buttonMode = true;			
			circle.useHandCursor = true;	
			return circle;
		}
		///////////////////////////////////////////////////////////
		private function startMoveEndLine(e:MouseEvent) {
			this.activeEnd = "End";
			if(this.endEntity != null){
				this.endEntity.removeLink(this);
				this.endEntity = null;
			}	
			dispatchEvent(new Event(Entity.ENTITY_ON_DOWN));
		}
		
		private function stopMoveEndLine(e:MouseEvent) {
			dispatchEvent(new Event(Entity.ENTITY_ON_UP));			
		}
		////
		private function startMoveStartLine(e:MouseEvent) {
			this.activeEnd = "Start";
			if(this.startEntity !=null ){
				this.startEntity.removeLink(this);
				this.startEntity = null;
			}	
			dispatchEvent(new Event(Entity.ENTITY_ON_DOWN));
		}
		
		private function stopMoveStartLine(e:MouseEvent) {
			dispatchEvent(new Event(Entity.ENTITY_ON_UP));
		}
		
		public override function doActionOnDown():void {			
			if (this.activeEnd == "End") {				
				this.endLine.startDrag();	
				parent.addEventListener(MouseEvent.MOUSE_MOVE, onMoveEndLine);
			}	
			if (this.activeEnd == "Start") {
				this.startLine.startDrag();
				parent.addEventListener(MouseEvent.MOUSE_MOVE,  onMoveStartLine);
			}			
			this.illuminateObj.graphics.moveTo(this.startLine.x, this.startLine.y);
			this.illuminateObj.graphics.lineTo(this.endLine.x, this.endLine.y);			
			this.addChildAt(this.illuminateObj, 0);
		}
		
		public override function doActionOnUp():void {		
			var el = null;
			var p1, p2, p3, p4:Point;
			if(this.activeEnd == "End"){
				parent.removeEventListener(MouseEvent.MOUSE_MOVE, onMoveEndLine);
				this.endLine.stopDrag();				
				p1 = new Point(this.endLine.x, this.endLine.y);
				p1 = this.localToGlobal(p1);
				p2 = new Point(this.endLine.x + this.endLine.width, this.endLine.y);			
				p2 = this.localToGlobal(p2);
				p3 = new Point(this.endLine.x, this.endLine.y + this.endLine.height);
				p3 = this.localToGlobal(p3);
				p4 = new Point(this.endLine.x + this.endLine.width, this.endLine.y + this.endLine.height);
				p4 = this.localToGlobal(p4);				
			}
			if(this.activeEnd == "Start"){
				parent.removeEventListener(MouseEvent.MOUSE_MOVE,  onMoveStartLine);
				this.startLine.stopDrag();
				p1 = new Point(this.startLine.x, this.startLine.y);
				p1 = this.localToGlobal(p1);
				p2 = new Point(this.startLine.x + this.startLine.width, this.startLine.y);			
				p2 = this.localToGlobal(p2);
				p3 = new Point(this.startLine.x, this.startLine.y + this.startLine.height);
				p3 = this.localToGlobal(p3);
				p4 = new Point(this.startLine.x + this.startLine.width, this.startLine.y + this.startLine.height);
				p4 = this.localToGlobal(p4);				
			}
			if(p1!=null && p2!=null && p3!=null && p4!=null){
				var points:Array = new Array(p1,p2,p3,p4);				
				el = this.scheme.getDropEntity(points);			
				if(el!=null){
					if (el.addLink(this)) {	
						this.draw(el);				
					}else {
						var pc:Point;
						var pe:Point;
						if (this.activeEnd == "Start") {
							this.startEntity = el;
							pc = new Point(this.startLine.x, this.startLine.y);
							pe = new Point(this.endLine.x, this.endLine.y);
						}
						if (this.activeEnd == "End") {
							this.endEntity = el;
							pe = new Point(this.startLine.x, this.startLine.y);
							pc = new Point(this.endLine.x, this.endLine.y);
						}
						pc = this.localToGlobal(pc);
						pe = this.localToGlobal(pe);
						var pc = this.globalToLocal(el.getPointOutSide(pc, pe));
						if (this.activeEnd == "Start") {
							this.startLine.x = pc.x;
							this.startLine.y = pc.y;						
						}
						if (this.activeEnd == "End") {
							this.endLine.x = pc.x;
							this.endLine.y = pc.y;
						}
						this.reDrawLine(this.startLine,this.endLine);
					};
				}	
			}	
			this.activeEnd = null;			
		}
		
		private function reDrawLine(startPoint,endPoint) {
			this.line.graphics.clear();
			this.line.graphics.lineStyle(2, lColour);
			this.line.graphics.moveTo(startPoint.x, startPoint.y);
			this.line.graphics.lineTo(endPoint.x, endPoint.y);			
			this.illuminateObj.graphics.clear();
			if (this.contains(this.illuminateObj)) {			
				this.illuminateObj.graphics.lineStyle(2, 0x30b1e7);
				this.illuminateObj.graphics.moveTo(startPoint.x, startPoint.y);
				this.illuminateObj.graphics.lineTo(endPoint.x, endPoint.y);				
			}
		}
		
		
		private function draw(el) {
			var pc:Point;
			var pe:Point;
			if (this.activeEnd == "Start") {
				this.startEntity = el;
				pc = new Point(this.startLine.x, this.startLine.y);
				pe = new Point(this.endLine.x, this.endLine.y);
			}
			if (this.activeEnd == "End") {
				this.endEntity = el;
				pe = new Point(this.startLine.x, this.startLine.y);
				pc = new Point(this.endLine.x, this.endLine.y);
			}
			pc = this.localToGlobal(pc);
			pe = this.localToGlobal(pe);
			pc = this.globalToLocal(el.getConnectPoint(pc,pe,this));
			if (this.activeEnd == "Start") {
				this.startLine.x = pc.x;
				this.startLine.y = pc.y;						
			}
			if (this.activeEnd == "End") {
				this.endLine.x = pc.x;
				this.endLine.y = pc.y;
			}
			this.reDrawLine(this.startLine,this.endLine);		
		}
		
		public function reDraw(el) {
			if(el!=null){
				if (el == endEntity) {
					this.activeEnd = "End";
					this.draw(el);
				}
				if (el == startEntity ) {
					this.activeEnd = "Start";
					this.draw(el);
				}
			}
		}		
	
		private function onMoveEndLine(e:MouseEvent):void {			
			reDrawLine(this.startLine, this.endLine);
		}
		
		private function onMoveStartLine(e:MouseEvent):void {			
			reDrawLine(this.endLine,this.startLine)
		}
		//
		public override function getDictDesc(){
			var cL:CLink = new CLink();
			var d = new Dictionary();
			if (this.endEntity != null) {
				d["id"] = this.endEntity.getId();
				d["type"] = this.endEntity.getType();
				cL.end = d;
			}else{
				cL.end = null;
			}
			var d2 = new Dictionary();
			if (startEntity != null) {
				d2["id"] = this.startEntity.getId();
				d2["type"] = this.startEntity.getType();
				cL.start = d2;
			}else {
				cL.start = null;
			}
			//
			cL.id = this.id;
	//		cL.idBD = this.idBD;
			cL.name = this.nameElement;
			cL.description = this.description;
	//		cL.x = this.x;
	//		cL.y = this.y;	
			return cL;		
		}
		
		public function toXML():String {
			var str = "<link>";
			str += "<idinscheme>" + this.id + "</idinscheme>";
			str += "<idbd>"+this.idBD+"</idbd>";
			str += "<name>"+this.name+"</name>";
			str += "<desc>" + this.description + "</desc>";
			if(this.endEntity!=null){
				str += "<idendentity>" + this.endEntity.getId() + "</idendentity>";
			}
			if (this.startEntity != null) {
				str += "<idstartentity>" + this.startEntity.getId() + "</idstartentity>";
			}
			//str += "<x>"+this.x+"</x>";
			//str += "<y>"+this.y+"</y>";
			str += "</link>";
			return str;
		}
		
	}
	
}